diff -Naur xu4-1.2.1/src/intro.cpp u4-1.2.1/src/intro.cpp
--- xu4-1.2.1/src/intro.cpp	2022-12-28 11:16:16.000000000 -0500
+++ u4-1.2.1/src/intro.cpp	2022-12-12 17:42:19.000000000 -0500
@@ -48,8 +48,6 @@
 #define GYP_SEGUE1 13
 #define GYP_SEGUE2 14
 
-#define INTRO_CON       IntroController* ic = xu4.intro
-
 #ifndef GPU_RENDER
 class IntroObjectState {
 public:
@@ -59,6 +57,9 @@
 };
 #endif
 
+/* temporary place-holder for settings changes */
+SettingsData settingsChanged;
+
 const int IntroBinData::INTRO_TEXT_OFFSET = 17445 - 1;  // (start at zero)
 const int IntroBinData::INTRO_MAP_OFFSET = 30339;
 const int IntroBinData::INTRO_FIXUPDATA_OFFSET = 29806;
@@ -167,93 +168,20 @@
     return true;
 }
 
-//----------------------------------------------------------------------------
-
-struct SettingsMenus {
-    static void menusNotice(int, void*, void*);
-
-    SettingsMenus();
-
-    void showMenu(Menu *menu);
-    void drawMenu();
-    void dispatchMenu(const MenuEvent* event);
-    void saveSettings();
-    void updateConfMenu(int);
-    void updateVideoMenu(int);
-    void updateSoundMenu(int);
-
-    enum MenuConstants {
-        MI_CONF_VIDEO,
-        MI_CONF_SOUND,
-        MI_CONF_INPUT,
-        MI_CONF_SPEED,
-        MI_CONF_GAMEPLAY,
-        MI_CONF_INTERFACE,
-        MI_CONF_01,
-        MI_VIDEO_CONF_GFX,
-        MI_VIDEO_02,
-        MI_VIDEO_03,
-        MI_VIDEO_04,
-        MI_VIDEO_05,
-        MI_VIDEO_06,
-        MI_VIDEO_07,
-        MI_VIDEO_08,
-        MI_GFX_TILE_TRANSPARENCY,
-        MI_GFX_TILE_TRANSPARENCY_SHADOW_SIZE,
-        MI_GFX_TILE_TRANSPARENCY_SHADOW_OPACITY,
-        MI_GFX_RETURN,
-        MI_SOUND_01,
-        MI_SOUND_02,
-        MI_SOUND_03,
-        MI_INPUT_01,
-        MI_INPUT_02,
-        MI_INPUT_03,
-        MI_SPEED_01,
-        MI_SPEED_02,
-        MI_SPEED_03,
-        MI_SPEED_04,
-        MI_SPEED_05,
-        MI_SPEED_06,
-        MI_SPEED_07,
-        MI_GAMEPLAY_01,
-        MI_GAMEPLAY_02,
-        MI_GAMEPLAY_03,
-        MI_GAMEPLAY_04,
-        MI_GAMEPLAY_05,
-        MI_GAMEPLAY_06,
-        MI_INTERFACE_01,
-        MI_INTERFACE_02,
-        MI_INTERFACE_03,
-        MI_INTERFACE_04,
-        MI_INTERFACE_05,
-        MI_INTERFACE_06,
-        USE_SETTINGS = 0xFE,
-        CANCEL = 0xFF
-    };
-
-    Menu mainMenu;
-    Menu confMenu;
-    Menu videoMenu;
-    Menu gfxMenu;
-    Menu soundMenu;
-    Menu inputMenu;
-    Menu speedMenu;
-    Menu gameplayMenu;
-    Menu interfaceMenu;
-
-    Menu* active;
-    TextView extendedMenuArea;
-    int listenerId;
-
-    /* temporary place-holder for settings changes */
-    SettingsData settingsChanged;
-};
-
-SettingsMenus::SettingsMenus() :
-    extendedMenuArea(2 * CHAR_WIDTH, 10 * CHAR_HEIGHT, 36, 13)
+IntroController::IntroController() :
+    Controller(1),
+    backgroundArea(),
+    menuArea(1 * CHAR_WIDTH, 13 * CHAR_HEIGHT, 38, 11),
+    extendedMenuArea(2 * CHAR_WIDTH, 10 * CHAR_HEIGHT, 36, 13),
+    questionArea(INTRO_TEXT_X * CHAR_WIDTH, INTRO_TEXT_Y * CHAR_HEIGHT, INTRO_TEXT_WIDTH, INTRO_TEXT_HEIGHT),
+    mapArea(BORDER_WIDTH, (TILE_HEIGHT * 6) + BORDER_HEIGHT, INTRO_MAP_WIDTH, INTRO_MAP_HEIGHT),
+    binData(NULL),
+    titles(),                   // element list
+    title(titles.begin()),      // element iterator
+    bSkipTitles(false),
+    egaGraphics(true)
 {
-    active = &confMenu;
-
+    // initialize menus
     confMenu.setTitle("XU4 Configuration:", 0, 0);
     confMenu.add(MI_CONF_VIDEO,               "\010 Video Options",              2,  2,/*'v'*/  2);
     confMenu.add(MI_CONF_SOUND,               "\010 Sound Options",              2,  3,/*'s'*/  2);
@@ -267,8 +195,8 @@
     confMenu.setClosesMenu(CANCEL);
 
     /* set the default visibility of the two enhancement menus */
-    confMenu.itemOfId(MI_CONF_GAMEPLAY)->setVisible(xu4.settings->enhancements);
-    confMenu.itemOfId(MI_CONF_INTERFACE)->setVisible(xu4.settings->enhancements);
+    confMenu.getItemById(MI_CONF_GAMEPLAY)->setVisible(xu4.settings->enhancements);
+    confMenu.getItemById(MI_CONF_INTERFACE)->setVisible(xu4.settings->enhancements);
 
     videoMenu.setTitle("Video Options:", 0, 0);
     videoMenu.add(MI_VIDEO_CONF_GFX,              "\010 Game Graphics Options",  2,  2,/*'g'*/  2);
@@ -306,7 +234,7 @@
     inputMenu.setTitle("Keyboard Options:", 0, 0);
     inputMenu.add(MI_INPUT_01,  new IntMenuItem("Repeat Delay        %4d msec", 2,  2,/*'d'*/  7, &settingsChanged.keydelay, 100, MAX_KEY_DELAY, 100));
     inputMenu.add(MI_INPUT_02,  new IntMenuItem("Repeat Interval     %4d msec", 2,  3,/*'i'*/  7, &settingsChanged.keyinterval, 10, MAX_KEY_INTERVAL, 10));
-    /* "Mouse Options:" is drawn in dispatchMenu() */
+    /* "Mouse Options:" is drawn in the updateInputMenu() function */
     inputMenu.add(MI_INPUT_03, new BoolMenuItem("Mouse                %s",      2,  7,/*'m'*/  0, &settingsChanged.mouseOptions.enabled));
     inputMenu.add(USE_SETTINGS,                 "\010 Use These Settings",      2, 11,/*'u'*/  2);
     inputMenu.add(CANCEL,                       "\010 Cancel",                  2, 12,/*'c'*/  2);
@@ -357,198 +285,7 @@
     interfaceMenu.setClosesMenu(CANCEL);
 }
 
-/*
- * Set the active menu.
- */
-void SettingsMenus::showMenu(Menu *menu)
-{
-    active = menu;
-    menu->reset();
-}
-
-void SettingsMenus::drawMenu()
-{
-    // draw the extended background for all option screens
-    // beasties are always visible on the menus
-    INTRO_CON;
-    ic->backgroundArea.draw(BKGD_OPTIONS_TOP, 0, 0);
-    ic->backgroundArea.draw(BKGD_OPTIONS_BTM, 0, 120);
-    ic->drawBeasties();
-
-    active->show(&extendedMenuArea);
-
-    // after drawing the menu, extra menu text can be added here
-    if (active == &inputMenu)
-        extendedMenuArea.textAt(0, 5, "Mouse Options:");
-    else if (active == &interfaceMenu)
-        extendedMenuArea.textAt(2, 3, "  (Open, Jimmy, etc.)");
-
-    screenUploadToGPU();
-}
-
-/*
- * Update the screen when an observed menu is reset or has an item
- * activated.
- */
-void SettingsMenus::menusNotice(int sender, void* eventData, void* user) {
-    ((SettingsMenus*) user)->dispatchMenu((MenuEvent*) eventData);
-}
-
-void SettingsMenus::saveSettings() {
-    xu4.settings->setData(settingsChanged);
-    xu4.settings->write();
-}
-
-void SettingsMenus::dispatchMenu(const MenuEvent* event)
-{
-    const Menu* menu = event->menu;
-
-    //printf("KR menu %d\n", event->type);
-
-    if (event->type == MenuEvent::ACTIVATE ||
-        event->type == MenuEvent::INCREMENT ||
-        event->type == MenuEvent::DECREMENT)
-    {
-        int itemId = event->item->getId();
-
-        if (menu == &confMenu) {
-            updateConfMenu(itemId);
-        }
-        else if (menu == &videoMenu) {
-            updateVideoMenu(itemId);
-        }
-        else if (menu == &gfxMenu) {
-            if(itemId == MI_GFX_RETURN)
-                showMenu(&videoMenu);
-        }
-        else if (menu == &soundMenu) {
-            updateSoundMenu(itemId);
-        }
-        else if (menu == &inputMenu) {
-            if (itemId == USE_SETTINGS) {
-                saveSettings();
-                screenShowMouseCursor(xu4.settings->mouseOptions.enabled);
-            }
-        }
-        else if (menu == &speedMenu) {
-            if (itemId == USE_SETTINGS) {
-                saveSettings();
-
-                // re-initialize events
-                xu4.eventHandler->setTimerInterval(1000 / xu4.settings->gameCyclesPerSecond);
-            }
-        }
-        else if (menu == &gameplayMenu ||
-                 menu == &interfaceMenu) {
-            if (itemId == USE_SETTINGS)
-                saveSettings();
-        }
-
-        if (itemId == CANCEL)
-            settingsChanged = *xu4.settings;    // discard settings
-    }
-
-    drawMenu();
-}
-
-void SettingsMenus::updateConfMenu(int itemId) {
-    // show or hide game enhancement options if enhancements are enabled/disabled
-    confMenu.itemOfId(MI_CONF_GAMEPLAY)->setVisible(settingsChanged.enhancements);
-    confMenu.itemOfId(MI_CONF_INTERFACE)->setVisible(settingsChanged.enhancements);
-
-    saveSettings();
-
-    switch(itemId) {
-    case MI_CONF_VIDEO:
-        showMenu(&videoMenu);
-        break;
-    case MI_VIDEO_CONF_GFX:
-        showMenu(&gfxMenu);
-        break;
-    case MI_CONF_SOUND:
-        showMenu(&soundMenu);
-        break;
-    case MI_CONF_INPUT:
-        showMenu(&inputMenu);
-        break;
-    case MI_CONF_SPEED:
-        showMenu(&speedMenu);
-        break;
-    case MI_CONF_GAMEPLAY:
-        showMenu(&gameplayMenu);
-        break;
-    case MI_CONF_INTERFACE:
-        showMenu(&interfaceMenu);
-        break;
-    }
-}
-
-void SettingsMenus::updateVideoMenu(int itemId) {
-    switch(itemId) {
-    case USE_SETTINGS:
-        /* save settings (if necessary) */
-        if (*xu4.settings != settingsChanged) {
-            saveSettings();
-
-            /* FIXME: resize images, etc. */
-            INTRO_CON;
-            ic->deleteIntro();  // delete intro stuff
-            screenReInit();
-            ic->init();         // re-fix the backgrounds and scale images, etc.
-
-            // go back to menu mode
-            ic->mode = IntroController::INTRO_MENU;
-        }
-        break;
-    case MI_VIDEO_CONF_GFX:
-        showMenu(&gfxMenu);
-        break;
-    }
-}
-
-void SettingsMenus::updateSoundMenu(int itemId) {
-    switch(itemId) {
-        case MI_SOUND_01:
-            musicSetVolume(settingsChanged.musicVol);
-            break;
-        case MI_SOUND_02:
-            soundSetVolume(settingsChanged.soundVol);
-            soundPlay(SOUND_FLEE);
-            break;
-        case USE_SETTINGS:
-            saveSettings();
-            {
-            INTRO_CON;
-            musicPlay(ic->introMusic);
-            }
-            break;
-        case CANCEL:
-            musicSetVolume(xu4.settings->musicVol);
-            soundSetVolume(xu4.settings->soundVol);
-            break;
-    }
-}
-
-//----------------------------------------------------------------------------
-
-IntroController::IntroController() :
-    Controller(1),
-    backgroundArea(),
-    menuArea(1 * CHAR_WIDTH, 13 * CHAR_HEIGHT, 38, 11),
-    questionArea(INTRO_TEXT_X * CHAR_WIDTH, INTRO_TEXT_Y * CHAR_HEIGHT, INTRO_TEXT_WIDTH, INTRO_TEXT_HEIGHT),
-    mapArea(BORDER_WIDTH, (TILE_HEIGHT * 6) + BORDER_HEIGHT, INTRO_MAP_WIDTH, INTRO_MAP_HEIGHT),
-    menus(NULL),
-    binData(NULL),
-    titles(),                   // element list
-    title(titles.begin()),      // element iterator
-    bSkipTitles(false),
-    egaGraphics(true)
-{
-}
-
 IntroController::~IntroController() {
-    delete menus;
-
     for (unsigned i=0; i < titles.size(); i++) {
         delete titles[i].srcImage;
         delete titles[i].destImage;
@@ -558,10 +295,12 @@
 bool IntroController::present() {
     init();
     preloadMap();
+    listenerId = gs_listen(1<<SENDER_MENU, introNotice, this);
     return true;
 }
 
 void IntroController::conclude() {
+    gs_unplug(listenerId);
     deleteIntro();
 }
 
@@ -637,8 +376,7 @@
 
     backgroundArea.reinit();
     menuArea.reinit();
-    if (menus)
-        menus->extendedMenuArea.reinit();
+    extendedMenuArea.reinit();
     questionArea.reinit();
     mapArea.reinit();
 
@@ -714,17 +452,10 @@
             MAP_ENABLE;
             break;
         case 'c': {
-            if (! menus)
-               menus = new SettingsMenus;
-
             // Make a copy of our settings so we can change them
-            menus->settingsChanged = *xu4.settings;
+            settingsChanged = *xu4.settings;
             screenHideCursor();
-            menus->listenerId = gs_listen(1<<SENDER_MENU, menus->menusNotice,
-                                          menus);
-            menus->showMenu(&menus->confMenu);
-            runMenu(&menus->confMenu, &menus->extendedMenuArea, true);
-            gs_unplug(menus->listenerId);
+            runMenu(&confMenu, &extendedMenuArea, true);
             screenShowCursor();
             updateScreen();
             break;
@@ -1489,6 +1220,289 @@
 }
 
 /**
+ * Update the screen when an observed menu is reset or has an item
+ * activated.
+ * TODO, reduce duped code.
+ */
+void IntroController::introNotice(int sender, void* eventData, void* user) {
+    MenuEvent* event = (MenuEvent*) eventData;
+    ((IntroController*) user)->dispatchMenu(event->menu, *event);
+}
+
+void IntroController::dispatchMenu(const Menu *menu, MenuEvent &event) {
+    if (menu == &confMenu)
+        updateConfMenu(event);
+    else if (menu == &videoMenu)
+        updateVideoMenu(event);
+    else if (menu == &gfxMenu)
+        updateGfxMenu(event);
+    else if (menu == &soundMenu)
+        updateSoundMenu(event);
+    else if (menu == &inputMenu)
+        updateInputMenu(event);
+    else if (menu == &speedMenu)
+        updateSpeedMenu(event);
+    else if (menu == &gameplayMenu)
+        updateGameplayMenu(event);
+    else if (menu == &interfaceMenu)
+        updateInterfaceMenu(event);
+
+    // beasties are always visible on the menus
+    drawBeasties();
+}
+
+void IntroController::updateConfMenu(MenuEvent &event) {
+    if (event.type == MenuEvent::ACTIVATE ||
+        event.type == MenuEvent::INCREMENT ||
+        event.type == MenuEvent::DECREMENT) {
+
+        // show or hide game enhancement options if enhancements are enabled/disabled
+        confMenu.getItemById(MI_CONF_GAMEPLAY)->setVisible(settingsChanged.enhancements);
+        confMenu.getItemById(MI_CONF_INTERFACE)->setVisible(settingsChanged.enhancements);
+
+        // save settings
+        xu4.settings->setData(settingsChanged);
+        xu4.settings->write();
+
+        switch(event.item->getId()) {
+        case MI_CONF_VIDEO:
+            runMenu(&videoMenu, &extendedMenuArea, true);
+            break;
+        case MI_VIDEO_CONF_GFX:
+            runMenu(&gfxMenu, &extendedMenuArea, true);
+            break;
+        case MI_CONF_SOUND:
+            runMenu(&soundMenu, &extendedMenuArea, true);
+            break;
+        case MI_CONF_INPUT:
+            runMenu(&inputMenu, &extendedMenuArea, true);
+            break;
+        case MI_CONF_SPEED:
+            runMenu(&speedMenu, &extendedMenuArea, true);
+            break;
+        case MI_CONF_GAMEPLAY:
+            runMenu(&gameplayMenu, &extendedMenuArea, true);
+            break;
+        case MI_CONF_INTERFACE:
+            runMenu(&interfaceMenu, &extendedMenuArea, true);
+            break;
+        case CANCEL:
+            // discard settings
+            settingsChanged = *xu4.settings;
+            break;
+        default: break;
+        }
+    }
+
+    // draw the extended background for all option screens
+    backgroundArea.draw(BKGD_OPTIONS_TOP, 0, 0);
+    backgroundArea.draw(BKGD_OPTIONS_BTM, 0, 120);
+}
+
+void IntroController::updateVideoMenu(MenuEvent &event) {
+    if (event.type == MenuEvent::ACTIVATE ||
+        event.type == MenuEvent::INCREMENT ||
+        event.type == MenuEvent::DECREMENT) {
+
+        switch(event.item->getId()) {
+        case USE_SETTINGS:
+            /* save settings (if necessary) */
+            if (*xu4.settings != settingsChanged) {
+                xu4.settings->setData(settingsChanged);
+                xu4.settings->write();
+
+                /* FIXME: resize images, etc. */
+                deleteIntro();  // delete intro stuff
+                screenReInit();
+                init();         // re-fix the backgrounds and scale images, etc.
+
+                // go back to menu mode
+                mode = INTRO_MENU;
+            }
+            break;
+        case MI_VIDEO_CONF_GFX:
+            runMenu(&gfxMenu, &extendedMenuArea, true);
+            break;
+        case CANCEL:
+            // discard settings
+            settingsChanged = *xu4.settings;
+            break;
+        default: break;
+        }
+    }
+
+    // draw the extended background for all option screens
+    backgroundArea.draw(BKGD_OPTIONS_TOP, 0, 0);
+    backgroundArea.draw(BKGD_OPTIONS_BTM, 0, 120);
+}
+
+void IntroController::updateGfxMenu(MenuEvent &event)
+{
+    if (event.type == MenuEvent::ACTIVATE ||
+        event.type == MenuEvent::INCREMENT ||
+        event.type == MenuEvent::DECREMENT) {
+
+
+        switch(event.item->getId()) {
+        case MI_GFX_RETURN:
+            runMenu(&videoMenu, &extendedMenuArea, true);
+            break;
+        default: break;
+        }
+    }
+
+    // draw the extended background for all option screens
+    backgroundArea.draw(BKGD_OPTIONS_TOP, 0, 0);
+    backgroundArea.draw(BKGD_OPTIONS_BTM, 0, 120);
+}
+
+void IntroController::updateSoundMenu(MenuEvent &event) {
+    if (event.type == MenuEvent::ACTIVATE ||
+        event.type == MenuEvent::INCREMENT ||
+        event.type == MenuEvent::DECREMENT) {
+
+        switch(event.item->getId()) {
+            case MI_SOUND_01:
+                musicSetVolume(settingsChanged.musicVol);
+                break;
+            case MI_SOUND_02:
+                soundSetVolume(settingsChanged.soundVol);
+                soundPlay(SOUND_FLEE);
+                break;
+            case USE_SETTINGS:
+                // save settings
+                xu4.settings->setData(settingsChanged);
+                xu4.settings->write();
+                musicPlay(introMusic);
+                break;
+            case CANCEL:
+                musicSetVolume(xu4.settings->musicVol);
+                soundSetVolume(xu4.settings->soundVol);
+                // discard settings
+                settingsChanged = *xu4.settings;
+                break;
+            default: break;
+        }
+    }
+
+    // draw the extended background for all option screens
+    backgroundArea.draw(BKGD_OPTIONS_TOP, 0, 0);
+    backgroundArea.draw(BKGD_OPTIONS_BTM, 0, 120);
+}
+
+void IntroController::updateInputMenu(MenuEvent &event) {
+    if (event.type == MenuEvent::ACTIVATE ||
+        event.type == MenuEvent::INCREMENT ||
+        event.type == MenuEvent::DECREMENT) {
+
+        switch(event.item->getId()) {
+        case USE_SETTINGS:
+            // save settings
+            xu4.settings->setData(settingsChanged);
+            xu4.settings->write();
+
+            // re-initialize keyboard
+            EventHandler::setKeyRepeat(settingsChanged.keydelay, settingsChanged.keyinterval);
+#ifndef IOS
+            screenShowMouseCursor(xu4.settings->mouseOptions.enabled);
+#endif
+            break;
+        case CANCEL:
+            // discard settings
+            settingsChanged = *xu4.settings;
+            break;
+        default: break;
+        }
+    }
+
+    // draw the extended background for all option screens
+    backgroundArea.draw(BKGD_OPTIONS_TOP, 0, 0);
+    backgroundArea.draw(BKGD_OPTIONS_BTM, 0, 120);
+
+    // after drawing the menu, extra menu text can be added here
+    extendedMenuArea.textAt(0, 5, "Mouse Options:");
+}
+
+void IntroController::updateSpeedMenu(MenuEvent &event) {
+    if (event.type == MenuEvent::ACTIVATE ||
+        event.type == MenuEvent::INCREMENT ||
+        event.type == MenuEvent::DECREMENT) {
+
+        switch(event.item->getId()) {
+        case USE_SETTINGS:
+            // save settings
+            xu4.settings->setData(settingsChanged);
+            xu4.settings->write();
+
+            // re-initialize events
+            xu4.eventHandler->setTimerInterval(1000 /
+                                        xu4.settings->gameCyclesPerSecond);
+            break;
+        case CANCEL:
+            // discard settings
+            settingsChanged = *xu4.settings;
+            break;
+        default: break;
+        }
+    }
+
+    // draw the extended background for all option screens
+    backgroundArea.draw(BKGD_OPTIONS_TOP, 0, 0);
+    backgroundArea.draw(BKGD_OPTIONS_BTM, 0, 120);
+}
+
+void IntroController::updateGameplayMenu(MenuEvent &event) {
+    if (event.type == MenuEvent::ACTIVATE ||
+        event.type == MenuEvent::INCREMENT ||
+        event.type == MenuEvent::DECREMENT) {
+
+        switch(event.item->getId()) {
+        case USE_SETTINGS:
+            // save settings
+            xu4.settings->setData(settingsChanged);
+            xu4.settings->write();
+            break;
+        case CANCEL:
+            // discard settings
+            settingsChanged = *xu4.settings;
+            break;
+        default: break;
+        }
+    }
+
+    // draw the extended background for all option screens
+    backgroundArea.draw(BKGD_OPTIONS_TOP, 0, 0);
+    backgroundArea.draw(BKGD_OPTIONS_BTM, 0, 120);
+}
+
+void IntroController::updateInterfaceMenu(MenuEvent &event) {
+    if (event.type == MenuEvent::ACTIVATE ||
+        event.type == MenuEvent::INCREMENT ||
+        event.type == MenuEvent::DECREMENT) {
+
+        switch(event.item->getId()) {
+            case USE_SETTINGS:
+                // save settings
+                xu4.settings->setData(settingsChanged);
+                xu4.settings->write();
+                break;
+            case CANCEL:
+                // discard settings
+                settingsChanged = *xu4.settings;
+                break;
+            default: break;
+        }
+    }
+
+    // draw the extended background for all option screens
+    backgroundArea.draw(BKGD_OPTIONS_TOP, 0, 0);
+    backgroundArea.draw(BKGD_OPTIONS_BTM, 0, 120);
+
+    // after drawing the menu, extra menu text can be added here
+    extendedMenuArea.textAt(2, 3, "  (Open, Jimmy, etc.)");
+}
+
+/**
  * Initializes the question tree.  The tree starts off with the first
  * eight entries set to the numbers 0-7 in a random order.
  */
